<?php

namespace app\merchants\services;

use app\common\loader\ModelMerchant;
use app\common\loader\ModelShop;
use app\common\loader\Services;
use app\merchants\libs\ManageToken;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\facade\Cache;
use yiqiniu\extend\exception\ApiException;
use yiqiniu\extend\facade\Db;

class MerchantService
{
    // 登录缓存有效期
    protected const TOKEN_TIMEOUT = DAY_SECOND * 3;
    // 登录权限的前缀
    protected const TOKEN_PREFIX = 'MERCHANT_LOGIN_TOKEN';

    /**
     * 商户登录
     * @param string $username
     * @param string $password
     * @param string $key
     * @param int $app
     * @return mixed
     * @throws Exception
     */
    public function login(string $username, string $password, string $key, int $app = 9)
    {
        if (empty($username) || empty($password)) {
            api_exception(API_ERROR, '用户名或密码不能为空');
        }
        $adminInfo = ModelMerchant::Merchant()
            ->where('mer_id', $key)
            ->where("username|mobile", $username)->where("status", 1)
            ->field("id,mer_id,passwd,dept_id,username")
            ->find();
        if (empty($adminInfo)) {
            api_exception(API_ERROR, '商户不存在或已被禁用');
        }
        if (md5(md5($password)) !== $adminInfo["passwd"]) {
            api_exception(API_ERROR, '密码错误,请重新登录。。');
        }
        $mer_status = ModelMerchant::MerchantInfo()->checkMerchantStatus($adminInfo['mer_id']);
        if (empty($mer_status)) {
            api_exception(API_ERROR, '商户已被禁用,请联系客服');
        }
        //生成加密TOKEN
        $authorization = $this->saveToken($adminInfo["id"], $adminInfo['passwd'], $app);
        $departmentName = ModelMerchant::MerchantDepartment()->where("id", $adminInfo["dept_id"])->value(null, "title");
        ModelMerchant::Merchant()->removeOption()->where('id', $adminInfo['id'])->update([], [
            'last_login_ip' => request()->ip(),
            'last_login_time' => Dt()->format(),
            'login_num' => Db::raw('login_num+1')
        ]);
        return [
            'authorization' => $authorization,
            "info" => [
                "true_name" => $adminInfo["username"],
                "department_name" => $departmentName
            ]
        ];
    }

    /**
     * 验证登录
     * @param $authorization
     * @param $app
     * @param string $msg 错误信息
     * @return array|false
     * @throws Exception
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws ApiException
     */
    public function verityLogin($authorization, $app, string &$msg)
    {

        $userInfo = ManageToken::getInstance()->verifyToken($authorization, $app);
        // 验证token是否成功 和 判断用户唯一性

        $cache = Cache::get(self::TOKEN_PREFIX . get_app($app) . '_' . $userInfo['id']);

        if (empty($cache) || $cache !== $authorization) {
            api_exception(API_TIMEOUT, '登录已过期或该账户在其他设备登录');
        }
        // 验证用户名 和密码 是否正确,判断用户是否禁用
        $adminInfo = ModelMerchant::Merchant()->validUserInfo($userInfo, $msg);
        if (empty($adminInfo)) {
            return false;
        }
        $mer_status = ModelMerchant::MerchantInfo()->checkMerchantStatus($adminInfo['mer_id']);
        if (empty($mer_status)) {
            $msg = '商户已被禁用,请联系客服';
            return false;
        }
        return [
            "admin_id" => $adminInfo["id"],
            "mer_id" => $adminInfo["mer_id"],
            "admin_name" => $adminInfo["username"],
            "group_id" => $adminInfo["role_id"],
            "department_id" => $adminInfo["dept_id"],
            'super' => $adminInfo['is_manager'] ?? 0
        ];
    }

    /**
     * 检测认证的权限
     * @param string $path 检测地址
     * @param int $role_id 检测解色组
     * @return bool true  认证成功 false 认证失败
     */
    public function checkAuthPermission(string $path, int $role_id): bool
    {
        if (ModelMerchant::MerchantRoles()->where('id', $role_id)->where('is_sys', 1)->count() > 0) {
            return true;
        }
        return ModelMerchant::MerchantRolesActions()->checkAuthPathExist($role_id, $path);
    }


    /**
     * 保存到token到缓存中
     * @param int $id 用户编号
     * @param string $password 密码
     * @param int $app app类型
     * @return mixed
     * @throws \yiqiniu\extend\exception\ApiException
     */
    private function saveToken(int $id, string $password, int $app = 9)
    {
        //生成加密TOKEN
        $tokens = config('config.token', []);
        $tokenKey = $tokens['jwt'] ?? '';
        if (empty($tokenKey)) {
            api_exception(401, 'secret_key不能为空');
        }
        $token = Services::Helper()->getToken($tokenKey, $tokens['expire'] ?? 0, ['id' => $id, 'password' => $password, 'app' => $app]);
        $authorization = $token['access_token'] ?? '';
        if (empty($authorization)) {
            api_exception(401, 'access_token加密有误');
        }
        //保存TOKEN入缓存
        Cache::set(self::TOKEN_PREFIX . get_app($app) . '_' . $id, $authorization, self::TOKEN_TIMEOUT);
        return $authorization;
    }

    /**
     * @title 商户列表
     * @param array $options
     * @return array
     * @throws Exception
     * @throws DbException
     */
    public function getPage(array $options): array
    {
        $list = ModelMerchant::Merchant()->filter(function ($v) {
            if ($v['is_manager'] !== 0) $v['username'] .= ' (超级管理员)';
            return $v;
        })->where($options['where'])
            ->order('id desc')->field('id,dept_id,open_id,role_id,username,is_manager,mobile,status,last_login_time,login_num,nickname,head_img,create_at')
            ->paginate(['page' => $options['page'], 'list_rows' => $options['page_size']]);

        Services::Helper()->showListTitle($list['data'], ['role' => 'role_id', 'dept' => 'dept_id']);
        return $list;
    }

    /**
     * @title 商户列表
     * @param array $options
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DbException
     */
    public function getList(array $options): array
    {
        if (empty($options['field'])) {
            $options['field'] = 'id,dept_id,username,is_manager,mobile,status';
        }
        return ModelMerchant::Merchant()->select($options);
    }

    /**
     * 编辑商户
     * @param $params
     * @return int|mixed|string
     * @throws Exception
     * @throws \think\db\exception\DbException
     */
    public function saveMerchant($params)
    {
        $id = $params['id'] ?? 0;
        unset($params['id']);
        $params['update_at'] = Dt()->format();
        if (!empty($params["passwd"])) {
            $params["repeat_passwd"] = $params["repeat_passwd"] ?? "";
            if ($params["passwd"] !== $params["repeat_passwd"]) {
                api_exception(400, '密码填写不一致，请重新设置');
            }
            $params["passwd"] = md5(md5($params["passwd"]));
        } else {
            unset($params["passwd"]);
        }
        $check = ModelMerchant::Merchant()->checkMobile($params['mer_id'] ?? '', $params['mobile'] ?? '', $params['username'] ?? '');
        if (!empty($id)) {
            if (!empty($check) && $check != $id) {
                api_exception(400, '用户已存在');
            }
            ModelMerchant::Merchant()->where('id', $id)->update([], $params);
        } else {
            if (empty($params["passwd"])) {
                $params["passwd"] = md5(md5('654321'));
            }
            if (!empty($check)) {
                api_exception(400, '手机号已存在');
            }
            $id = ModelMerchant::Merchant()->insert($params, true);
        }
        return $id;
    }

    /**
     * @title 商户详情
     * @param array $options
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DbException
     */
    public function getInfo(array $options): array
    {
        if (empty($options['field'])) {
            $options['field'] = 'id,dept_id,role_id,username,is_manager,mobile,status,last_login_time,login_num,create_at';
        }
        $info = ModelMerchant::Merchant()->find($options);
        if (empty($info)) {
            api_exception(400, '管理员不存在或已删除');
        }
        return $info;
    }

    /**
     * @title 删除商户
     * @param array $where
     * @return bool
     * @throws Exception
     */
    public function delMerchant(array $where): bool
    {
        if (empty($where)) {
            return true;
        }
        $info = $this->getInfo(['where' => $where]);
        if (!empty($info['is_manager']) && $info['is_manager'] == 1) {
            api_exception(400, '系统管理员暂不支持删除');
        }
        $data = ModelMerchant::Merchant()->where('id', $info['id'])->delete();
        if ($data) {
            ModelShop::Shop()->where('op_user', $info['id'])->update(null, ['op_user' => '']);
        }
        return true;
    }

    /**
     * 修改密码
     * @param int $id 商户ID
     * @param string $oldPassword 旧密码
     * @param string $password 新密码
     * @param int $app
     * @return array
     * @throws Exception
     */
    public function editPassword(int $id, string $oldPassword, string $password, int $app = 9): array
    {
        $model = ModelMerchant::Merchant();
        $info = $model->where('id', $id)->field('id,passwd')->find();
        if (empty($info)) {
            api_exception(API_ERROR, '商户信息不存在');
        }
        if ($info['passwd'] !== md5(md5($oldPassword))) {
            api_exception(API_ERROR, '旧密码错误');
        }
        $newPassword = md5(md5($password));
        if ($info['passwd'] === $newPassword) {
            api_exception(API_ERROR, '新旧密码一致,请重新设置');
        }
        $updateData = [
            'passwd' => $newPassword,
            'update_time' => Dt()->format()
        ];
        // 修改密码成功后,返回新的token
        $model->removeOption()->where('id', $id)->update(null, $updateData);
        $authorization = $this->saveToken($id, $newPassword, $app);
        return [
            'authorization' => $authorization,
        ];
    }

    /**
     * 微信解绑
     * @param array $where
     * @return void
     */
    public function saveOauth(array $where = []): void
    {
        try {
            $data = ModelMerchant::Merchant()->where($where)->update(null, [
                'open_id' => '', 'union_id' => '',
                'nickname' => '', 'head_img' => '']);
            if (!$data) {
                throw  new Exception('解绑失败', API_ERROR);
            }
        } catch (Exception $e) {
            api_result($e);
        }
    }
}
